/*
 * @Date: 2019-12-2
 * @Author: xuechengwu <xuechengwu@erayt.com>
 * @Description: 主图技术指标层
 */

import BaseLayer from './BaseLayer';
import ma from '../quota/ma';
import boll from '../quota/boll';
import Point from '../core/Point';
import MultiLine from '../base/MultiLine';
import Color from '../core/Color';
import env from '../quota/env';
/**
 * 要求返回当前的最大值，最小值和指标值
 * @param layer
 * @param data
 * @param start
 * @param end
 * @returns {{min: *, max: *, indicators: {name: string, value: *, key: string}[]}}
 */
const defaultIndicatorCaculator = (layer, data, start, end) => {
  const funcs = {
    /**
     * 移动平均线
     * @param layer
     * @param data
     * @param start
     * @param end
     * @returns {{min: *, max: *, indicators: {ma5: Array, ma20: Array, ma10: Array}, drawFun: drawFun}}
     */
    ma(layer, data, start, end) {
      const { N1 = 5, N2 = 10, N3 = 20 } = layer.params;
      let dataStart = start - N3;
      if (dataStart < 0) {
        dataStart = 0;
      }
      const close = [];
      for (let i = dataStart; i <= end; i++) {
        close.push(parseFloat(data[i].close));
      }
      const ma5 = ma(close, N1);
      const ma10 = ma(close, N2);
      const ma20 = ma(close, N3);
      const dataLen = (ma20.length > end - start + 1) ? (end - start + 1) : ma20.length;
      let max = ma5[ma5.length - dataLen];
      let min = ma5[ma5.length - dataLen];
      let ma5Data = [], ma10Data = [], ma20Data = [];
      for (let i = 1; i <= dataLen; i++) {
        if (max < ma5[ma5.length - i]) {
          max = ma5[ma5.length - i];
        }
        if (min > ma5[ma5.length - i]) {
          min = ma5[ma5.length - i];
        }
        if (max < ma10[ma10.length - i]) {
          max = ma10[ma10.length - i];
        }
        if (min > ma10[ma10.length - i]) {
          min = ma10[ma10.length - i];
        }
        if (max < ma20[ma20.length - i]) {
          max = ma20[ma20.length - i];
        }
        if (min > ma20[ma20.length - i]) {
          min = ma20[ma20.length - i];
        }
        ma5Data.unshift(ma5[ma5.length - i]);
        ma10Data.unshift(ma10[ma10.length - i]);
        ma20Data.unshift(ma20[ma20.length - i]);
      }
      const drawFun = (indicators, layer, options) => {
        const { ma5, ma10, ma20 } = indicators;
        const { xStep, yStep, xBase } = options;
        let ma5Points = [];
        let ma10Points = [];
        let ma20Points = [];
        for (let i = 0; i < ma5.length; i++) {
          ma5Points.push(new Point(i * xStep + layer.position.x, (ma5[i] - xBase) * yStep + layer.position.y));
          ma10Points.push(new Point(i * xStep + layer.position.x, (ma10[i] - xBase) * yStep + layer.position.y));
          ma20Points.push(new Point(i * xStep + layer.position.x, (ma20[i] - xBase) * yStep + layer.position.y));
        }
        let ma5Line = new MultiLine(layer.canvas,ma5Points);
        let ma10Line = new MultiLine(layer.canvas, ma10Points);
        let ma20Line = new MultiLine(layer.canvas, ma20Points);
        ma5Line.setColor(new Color('#DE5946'));
        ma10Line.setColor(new Color('#89CDA0'));
        ma20Line.setColor(new Color('#D67C89'));
        layer.addChild(ma5Line, ma10Line, ma20Line);
      }
      return {
        max,
        min,
        drawFun,
        indicators: {
          ma5: ma5Data,
          ma10: ma10Data,
          ma20: ma20Data
        }
      };
    },
    /**
     * 布林线
     * @param layer
     * @param data
     * @param start
     * @param end
     * @returns {{min: *, max: *, indicators: {middle: Array, low: Array, upper: Array}, drawFun: drawFun}}
     */
    boll(layer, data, start, end) {
      const { N = 20, width = 2 } = layer.params;
      let dataStart = start - N;
      if (dataStart < 0) {
        dataStart = 0;
      }
      const close = [];
      for (let i = dataStart; i <= end; i++) {
        close.push(parseFloat(data[i].close));
      }
      const { middle, upper, low } = boll(close, N, width);
      const dataLen = (middle.length > end - start + 1) ? (end - start + 1) : middle.length;
      let min = middle[middle.length - 1];
      let max = middle[middle.length -1];
      const middleData = [], upperData = [], lowData = [];
      for (let i = 1; i <= dataLen; i++) {
        if (min > low[low.length - i]) {
          min = low[low.length - i];
        }
        if (max < upper[upper.length - i]) {
          max = upper[upper.length - i];
        }
        middleData.unshift(middle[middle.length - i]);
        upperData.unshift(upper[upper.length - i]);
        lowData.unshift(low[low.length - i]);
      }

      const drawFun = (indicators, layer, options) => {
        const { upper, middle, low } = indicators;
        const { xStep, yStep, xBase } = options;
        let upperPoints = [];
        let middlePoints = [];
        let lowPoints = [];
        for (let i = 0; i < upper.length; i++) {
          upperPoints.push(new Point(i * xStep + layer.position.x, (upper[i] - xBase) * yStep + layer.position.y));
          middlePoints.push(new Point(i * xStep + layer.position.x, (middle[i] - xBase) * yStep + layer.position.y));
          lowPoints.push(new Point(i * xStep + layer.position.x, (low[i] - xBase) * yStep + layer.position.y));
        }
        let upperLine = new MultiLine(layer.canvas, upperPoints);
        let middleLine = new MultiLine(layer.canvas, middlePoints);
        let lowLine = new MultiLine(layer.canvas, lowPoints);
        upperLine.setColor(new Color('#23D4A3'));
        middleLine.setColor(new Color('#23D4A3'));
        lowLine.setColor(new Color('#23D4A3'));
        layer.addChild(upperLine, middleLine, lowLine);
      }
      return {
        max,
        min,
        drawFun,
        indicators: {
          upper: upperData,
          low: lowData,
          middle: middleData
        }
      };
    },
    /**
     * 通道指标
     * @param layer
     * @param data
     * @param start
     * @param end
     * @returns {{min: *, max: *, indicators: {middle: Array, low: Array, upper: Array}, drawFun: drawFun}}
     */
    env(layer, data, start, end) {
      const { N = 20, width = 0.02 } = layer.params;
      let dataStart = start - N;
      if (dataStart < 0) {
        dataStart = 0;
      }
      const close = [];
      for (let i = dataStart; i <= end; i++) {
        close.push(parseFloat(data[i].close));
      }
      const { UpperLine, MiddleLine, LowerLine } = env(close, width, N);
      const dataLen = (MiddleLine.length > end - start + 1) ? (end - start + 1) : MiddleLine.length;
      let min = MiddleLine[MiddleLine.length - 1];
      let max = MiddleLine[MiddleLine.length -1];
      const middleData = [], upperData = [], lowData = [];
      for (let i = 1; i <= dataLen; i++) {
        if (min > LowerLine[LowerLine.length - i]) {
          min = LowerLine[LowerLine.length - i];
        }
        if (max < UpperLine[UpperLine.length - i]) {
          max = UpperLine[UpperLine.length - i];
        }
        middleData.unshift(MiddleLine[MiddleLine.length - i]);
        upperData.unshift(UpperLine[UpperLine.length - i]);
        lowData.unshift(LowerLine[LowerLine.length - i]);
      }

      const drawFun = (indicators, layer, options) => {
        const { upper, middle, low } = indicators;
        const { xStep, yStep, xBase } = options;
        let upperPoints = [];
        let middlePoints = [];
        let lowPoints = [];
        for (let i = 0; i < upper.length; i++) {
          upperPoints.push(new Point(i * xStep + layer.position.x, (upper[i] - xBase) * yStep + layer.position.y));
          middlePoints.push(new Point(i * xStep + layer.position.x, (middle[i] - xBase) * yStep + layer.position.y));
          lowPoints.push(new Point(i * xStep + layer.position.x, (low[i] - xBase) * yStep + layer.position.y));
        }
        let upperLine = new MultiLine(layer.canvas, upperPoints);
        let middleLine = new MultiLine(layer.canvas, middlePoints);
        let lowLine = new MultiLine(layer.canvas, lowPoints);
        upperLine.setColor(new Color('#23D4A3'));
        middleLine.setColor(new Color('#23D4A3'));
        lowLine.setColor(new Color('#23D4A3'));
        layer.addChild(upperLine, middleLine, lowLine);
      }
      return {
        max,
        min,
        drawFun,
        indicators: {
          upper: upperData,
          low: lowData,
          middle: middleData
        }
      };
    },
    /**
     * 麦克指标
     * @param layer
     * @param data
     * @param start
     * @param end
     */
    mike(layer, data, start, end) {

    }
  }
  return funcs[layer.name](layer, data, start, end);
}

export default class IndicatorLayer extends BaseLayer {
  constructor(canvas, options) {
    super(canvas);
    this.width = options.width;
    this.height = options.height;
    this.data = options.data || [];
    this.dataStart = options.dataStart || 0;
    this.dataEnd = options.dataEnd || this.data.length;
    this.name = options.name || 'ma';
    this.params = options.params || {};
    this.indicatorCaculator = options.indicatorCaculator || defaultIndicatorCaculator
  }

  /**
   * 渲染
   */
  make() {
    this.childs.splice(0, this.childs.length);
    const { max, min, indicators, drawFun } = this.indicatorCaculator(this, this.data, this.dataStart, this.dataEnd);
    this.max = max;
    this.min = min;
    this.indicators = indicators;
    this.drawFun = drawFun;
    this.onMaked && this.onMaked({
      max,
      min,
      indicators,
    })
  }
}
